﻿// Created by Windward Studios - no copyright is claimed. This code can be used in
// any manner by anyone for any reason. There is no copyright of any kind on it. You may
// use it in commercial products. You may change it without sharing those changes.
// We ask that you keep the "created by Windward Studios" in a comment at the top.


using System;
using System.Collections;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Kailua.net.windward.utils
{
	/// <summary>
	/// System level utilities.
	/// </summary>
	public static class SystemUtils
	{

		/// <summary>
		/// Get all implemented types in a COM object. Code based on work at
		/// http://fernandof.wordpress.com/2008/02/05/how-to-check-the-type-of-a-com-object-system__comobject-with-visual-c-net/
		/// </summary>
		/// <param name="comObject">The object we want all types of.</param>
		/// <param name="assType">Any type in the COM assembly.</param>
		/// <returns>All implemented classes/interfaces.</returns>
		public static Type[] GetAllTypes(object comObject, Type assType)
		{
			// get the com object and fetch its IUnknown
			IntPtr iunkwn = Marshal.GetIUnknownForObject(comObject);

			// enum all the types defined in the interop assembly
			Assembly interopAss = Assembly.GetAssembly(assType);
			Type[] excelTypes = interopAss.GetTypes();

			// find all types it implements
			ArrayList implTypes = new ArrayList();
			foreach (Type currType in excelTypes)
			{
				// com interop type must be an interface with valid iid
				Guid iid = currType.GUID;
				if (!currType.IsInterface || iid == Guid.Empty)
					continue;

				// query supportability of current interface on object
				IntPtr ipointer;
				Marshal.QueryInterface(iunkwn, ref iid, out ipointer);

				if (ipointer != IntPtr.Zero)
					implTypes.Add(currType);
			}

			// no implemented type found
			return (Type[])implTypes.ToArray(typeof(Type));
		}
	}
}